
import java.net.InetAddress;
import java.net.UnknownHostException;



/**
 * Leaky bucket that listens on given port for incoming packets.
 * After applying shaping policy to packets they are sent to given address and port. 
 */
public class LeakyBucket implements Runnable
{
	// buffer for incoming packets
	private Buffer buffer;
	// thread in charge of removing packets from buffer and sending them
	private LeakyBucketSender sender;
	// thread in charge of receiving packets and putting them in buffer
	private LeakyBucketReceiver receiver;
	// thread in charge of generating and holding tokens
	private TokenBucket bucket;
	
	
	/**	  
	 * Constructor. Creates a buffer, receiver, sender, and token bucket class instances.
	 * @param inPort Port on which to listen for packets.
	 * @param outAddress IP address to which packets are sent.
	 * @param outPort Port to which packets are sent.
	 * @param maxPacketSize Maximum size of packet that will be received.
	 * @param bufferCapacity Capacity of buffer in bytes.
	 * @param bucketSize Number of tokens that leaky bucket can hold.
	 * @param bucketRate Token generating rate in tokens/sec.
	 * @param fileName Name of file leaky bucket uses to record packet arrivals.
	 */
	public LeakyBucket(int inPort, String outAddress, 
			int maxPacketSize, long bufferCapacity,
			int bucketSize, int bucketRate, String fileName)
	{
		if (bucketSize < maxPacketSize)
		{
			System.err.println("Bucket size should not be smaller than the maximum packet size!");
			System.err.println("Leaky bucket will be constructed with given parameters, but arrival of" + 
					"packet with size greater than bucket size will prevent sending of any further packets.");
		}
		Buffer.MAX_PACKET_SIZE = maxPacketSize;
		buffer = new Buffer(bufferCapacity);
		bucket = new TokenBucket(bucketSize, bucketRate);
		try
		{
			InetAddress destAddress = InetAddress.getByName(outAddress);
			sender = new LeakyBucketSender(buffer, destAddress, bucket);
		} 
		catch (UnknownHostException e)
		{
			e.printStackTrace();
		}
		receiver = new LeakyBucketReceiver(buffer, inPort, sender, bucket, fileName);
	}
	
	/**
	 * Start token bucket, receiver, and sender threads for leaky bucket.
	 * This method is invoked when starting a thread for this class. 
	 */
	public void run()
	{
		new Thread(bucket).start();
		new Thread(receiver).start();
		new Thread(sender).start();
	}
}
